package com.itaming.lycheeframework.support.tree;

import com.itaming.lycheeframework.common.constant.FrameworkConstant;
import com.itaming.lycheeframework.support.utils.CollectionUtil;
import com.itaming.lycheeframework.support.utils.NumberUtil;
import com.itaming.lycheeframework.support.utils.ObjectUtil;
import lombok.Setter;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 树形数据生成器
 *
 * @param <T> 节点类型
 * @param <S> 节点<code>id</code>和<code>parentId</code>类型
 * @author A.Ming
 */
@Accessors(chain = true)
@Setter
public class TreeBuilder<T extends TreeNode<T, S>, S extends Serializable> {

    /**
     * 树节点映射
     */
    private final Map<S, T> nodeMap;

    /**
     * 树数据
     */
    private final List<T> tree = new ArrayList<>();

    /**
     * 是否已生成
     */
    private boolean isBuilt = false;

    /**
     * 顶层父节点ID
     */
    private S topParentId;

    /**
     * 是否忽略没有父节点的悬空节点
     */
    private boolean ignoreDanglingNode = true;

    /**
     * 创建一个树形数据生成器
     *
     * @param nodes 节点数据列表
     * @return 树形数据生成器
     */
    public static <T extends TreeNode<T, S>, S extends Serializable> TreeBuilder<T, S> of(Collection<T> nodes) {
        return new TreeBuilder<>(nodes);
    }

    /**
     * 构造函数
     *
     * @param nodes 节点数据列表
     */
    private TreeBuilder(Collection<T> nodes) {
        if (CollectionUtil.isEmpty(nodes)) {
            nodeMap = Collections.emptyMap();
        } else {
            nodeMap = nodes.stream()
                .filter(ObjectUtil::isNotNull)
                .collect(Collectors.toMap(TreeNode::getId, node -> node, (oldValue, newValue) -> oldValue, LinkedHashMap::new));
        }
    }

    /**
     * 生成树形数据
     *
     * @return 树形数据
     */
    public List<T> build() {
        // 避免重复生成
        if (!isBuilt) {
            nodeMap.values().forEach((node) -> {
                // 顶级节点
                if (isTopNode(node)) {
                    tree.add(node);
                    return;
                }

                // 添加到父节点
                TreeNode<T, S> parent = nodeMap.getOrDefault(node.getParentId(), null);
                if (parent != null) {
                    parent.addChildren(node);
                    return;
                }

                // 不忽略悬空节点则视为顶级节点
                if (!ignoreDanglingNode) {
                    tree.add(node);
                }
            });

            // 标记为已生成
            isBuilt = true;
        }

        return tree;
    }

    /**
     * 是否为顶级节点
     *
     * @param node 节点
     * @return boolean
     */
    private boolean isTopNode(TreeNode<T, S> node) {
        if (node.getParentId() == null) {
            return true;
        }

        if (topParentId != null) {
            return topParentId.equals(node.getParentId());
        }

        return FrameworkConstant.TOP_PARENT_ID.equals(NumberUtil.toLong(node.getParentId()));
    }

}
